#pragma once

#include "Node.h"
#include "DesignEntityTable.h"

class AST{
public:
	/** Constructor
	 * Creates an empty AST or with specific node as the root of the AST.
	 * @param node the root node of the new AST.
	 */
	AST(Node* node = NULL);

	/**
	 * Set a specific node as the root of AST, this will also generate nodeIDs of the tree recursively
	 * @param node the root node of the new AST.
	 */
	void setRoot(Node* node);

	/**
	 * Get the root node of AST.
	 * @return the root node of AST, may be NULL.
	 */
	Node* AST::getRoot();

	/**
	 * Get a subtree of the AST.
	 * @param nodeID the root of the subtree.
	 * @return AST with the corresponding nodeID as root node, null if the nodeID does not exist.
	 */
	AST getSubTree(int nodeID);

	/**
	 * check if this AST is equal to the param.
	 * @param the AST to be compared.
	 * @return true if this AST is equal to the param AST, return false otherwise.
	 */
	bool equals(AST* otherAST);

	/**
	 * Add a node to design entity table.
	 * node the pointer to the node to be added.
	 */
	static void addToDETable(Node* node);

	/**
	 * Get the design entity table build during the creation of Nodes (every node should return the same instance).
	 * @return the design entity table.
	 */
	static DesignEntityTable* getDesignEntityTable();

private:
	Node *root; /**< the root node of this AST. */
	static DesignEntityTable designEntityTable; /**< the design entity table built during AST building */
	
	/**
	 * Check the descendants of specific node for presence of nodeID.
	 * @param node the specific node to be checked.
	 * @param nodeID the nodeID to look for.
	 * @return a node which matches the given nodeID, or NULL if not found.
	 */
	Node* checkDescendants(Node* node, int nodeID);

	/**
	 * Check if the subtree node1 is the same as the subtree node2
	 * @param node1 
	 * @param node2
	 * @return true if node1 subtree is equals to node2 subtree, return false otherwise
	 */
	bool compareSubTree(Node* node1, Node* node2);
};
